/*
 * Created by Jaren at 2022/1/29 11:32
 */
import 'dart:typed_data';

import 'package:binary/binary.dart';
import 'package:inmotion_protocol/base/vehicle_data.dart';
import 'package:inmotion_protocol/common/product_model.dart';
import 'package:inmotion_protocol/common/product_version.dart';
import 'package:inmotion_protocol/common/response.dart';
import 'package:inmotion_protocol/lorin/bean/common/bms_info.dart';
import 'package:inmotion_protocol/lorin/bean/euc/euc_statistics.dart';
import 'package:inmotion_protocol/lorin/constant.dart';
import 'package:inmotion_protocol/util/byte_util.dart';
import 'package:inmotion_protocol/util/version.dart';

class Response {
  int error;

  VersionWrapper? versionWrapper;
  ProductModel? model;

  Response(this.error);

  bool isSuccess() {
    return true;
  }
}

class ScooterCalibrationResultResponse extends AbsCalibrationResultResponse {
  _ScooterCalibrationResult? _result;

  ScooterCalibrationResultResponse(int result, ProductModel productModel, VersionWrapper version) : super(productModel, version) {
    if (productModel.isLS1Series()) {
      if (VersionUtils.higherOrEquals(version.getAppVersionByDevice(Constant.deviceS1Display), VersionConstant.s1Display130)) {
        _result = _ScooterCalibrationResultV2(result);
      } else {
        _result = _ScooterCalibrationResultV1(result);
      }
    } else {
      _result = _ScooterCalibrationResultV2(result);
    }
  }

  @override
  bool isCalibrating({int? which}) {
    return _result == null ? false : _result!.isCalibrating();
  }

  @override
  bool isCalibrateFailed({int? which}) {
    return _result == null ? false : _result!.isCalibrateFailed();
  }

  @override
  bool isCalibrateTimeout({int? which}) {
    return _result == null ? false : _result!.isCalibrateTimeout();
  }

  @override
  bool isCalibrateSucceed({int? which}) {
    return _result == null ? false : _result!.isCalibrated();
  }
}

abstract class _ScooterCalibrationResult {
  final int _result;

  _ScooterCalibrationResult(this._result);

  bool isCalibrated();

  bool isCalibrating();

  bool isCalibrateTimeout();

  bool isCalibrateFailed();

  int get result => _result;
}

class _ScooterCalibrationResultV1 extends _ScooterCalibrationResult {
  static const int calibrating = 1;
  static const int calibrated = 2;
  static const int timeout = 3;
  static const int failed = 4;

  _ScooterCalibrationResultV1(int result) : super(result);

  @override
  bool isCalibrated() {
    return result == calibrated;
  }

  @override
  bool isCalibrating() {
    return result == calibrating;
  }

  @override
  bool isCalibrateTimeout() {
    return result == timeout;
  }

  @override
  bool isCalibrateFailed() {
    return result == failed;
  }
}

class _ScooterCalibrationResultV2 extends _ScooterCalibrationResult {
  static const int waiting4Calibration = 1;
  static const int calibrating = 2;
  static const int calibrated = 3;
  static const int timeout = 4;
  static const int failed = 5;

  _ScooterCalibrationResultV2(int result) : super(result);

  @override
  bool isCalibrated() {
    return result == calibrated;
  }

  @override
  bool isCalibrating() {
    return result == calibrating || result == waiting4Calibration;
  }

  @override
  bool isCalibrateTimeout() {
    return result == timeout;
  }

  @override
  bool isCalibrateFailed() {
    return result == failed;
  }
}

/// 独轮车IMU校准回复
class EUCIMUCalibrationResultResponse extends AbsCalibrationResultResponse {
  int result0;
  int result1;
  int result2;

  //  0 - 空闲
  //  1 - 等待进行
  //  2 - 正在校正
  //  3 - 校正通过
  //  4 - 校正不通过
  //  5 - 校正超时

  EUCIMUCalibrationResultResponse(this.result0, this.result1, this.result2, ProductModel? productModel, VersionWrapper? version) : super(productModel, version);

  @override
  bool isCalibrateFailed({int? which}) {
    if (which == Constant.calibrationTurning) {
      return result0 == 4 || result2 == 4;
    }
    if (which == Constant.calibrationBalance) {
      return result0 == 4 || result1 == 4;
    }
    return false;
  }

  @override
  bool isCalibrateSucceed({int? which}) {
    if (which == Constant.calibrationTurning) {
      return result0 == 3 && result2 == 3;
    }
    if (which == Constant.calibrationBalance) {
      return result0 == 3 && result1 == 3;
    }
    return false;
  }

  @override
  bool isCalibrateTimeout({int? which}) {
    if (which == Constant.calibrationTurning) {
      return result0 == 5 || result2 == 5;
    }
    if (which == Constant.calibrationBalance) {
      return result0 == 5 || result1 == 5;
    }
    return false;
  }

  @override
  bool isCalibrating({int? which}) {
    if (which == Constant.calibrationTurning) {
      return (result0 == 1 || result0 == 2) || (result2 == 1 || result2 == 2);
    }
    if (which == Constant.calibrationBalance) {
      return (result0 == 1 || result0 == 2) || (result1 == 1 || result1 == 2);
    }
    return false;
  }
}

/// 电机适应进度Response
class MotorAutoCalibrateResultResponse extends AbsCalibrationResultResponse {
  /// 霍尔偏角校准
  int hallOffsetCompatState;

  /// 霍尔扇区校准
  int hallSectorCompatState;

  MotorAutoCalibrateResultResponse(this.hallOffsetCompatState, this.hallSectorCompatState) : super(null, null);

  /// 是否在自适应中
  @override
  bool isCalibrating({int? which}) {
    return hallOffsetCompatState == 1 || hallOffsetCompatState == 2 || hallSectorCompatState == 1 || hallSectorCompatState == 2;
  }

  /// 自适应成功
  @override
  bool isCalibrateSucceed({int? which}) {
    return hallOffsetCompatState == 3 && hallSectorCompatState == 3;
  }

  /// 自适应超时
  @override
  bool isCalibrateTimeout({int? which}) {
    return hallOffsetCompatState == 5 || hallSectorCompatState == 5;
  }

  /// 自适应失败
  @override
  bool isCalibrateFailed({int? which}) {
    return hallOffsetCompatState == 4 || hallSectorCompatState == 4;
  }

  static MotorAutoCalibrateResultResponse fromBytes(Uint8ClampedList bytes, [int offset = 0]) {
    return MotorAutoCalibrateResultResponse(bytes[offset], bytes[offset + 1]);
  }
}

/// 电机自检结果Response
class MotorSelfCheckResultResponse extends AbsCalibrationResultResponse {
  int state;

  MotorSelfCheckResultResponse(this.state) : super(null, null);

  @override
  bool isCalibrateFailed({int? which}) {
    return state == 4;
  }

  @override
  bool isCalibrateSucceed({int? which}) {
    return state == 3;
  }

  @override
  bool isCalibrateTimeout({int? which}) {
    return state == 5;
  }

  @override
  bool isCalibrating({int? which}) {
    return state == 1 || state == 2;
  }

  static MotorSelfCheckResultResponse fromBytes(Uint8ClampedList bytes, [int offset = 0]) {
    return MotorSelfCheckResultResponse(bytes[offset]);
  }
}

/// 电池校准结果Response
class BatteryCalibrationResultResponse extends AbsCalibrationResultResponse {
  int state;

  BatteryCalibrationResultResponse(this.state) : super(null, null);

  /// 是否在自检中
  @override
  bool isCalibrating({int? which}) {
    return state == 1 || state == 2;
  }

  /// 自检成功
  @override
  bool isCalibrateSucceed({int? which}) {
    return state == 3;
  }

  /// 自检超时
  @override
  bool isCalibrateTimeout({int? which}) {
    return state == 5;
  }

  /// 自检失败
  @override
  bool isCalibrateFailed({int? which}) {
    return state == 4;
  }

  static BatteryCalibrationResultResponse fromBytes(Uint8ClampedList bytes, [int offset = 0]) {
    return BatteryCalibrationResultResponse(bytes[offset]);
  }
}

abstract class StatisticsResponse extends Response {
  int index = 0;
  int count = 0;
  int total = 0;
  int length = 0;

  List<HistoryStatistics> statisticsList = [];

  StatisticsResponse(VersionWrapper versionWrapper, ProductModel model) : super(0) {
    this.versionWrapper = versionWrapper;
    this.model = model;
  }

  void fromBytes(Uint8ClampedList bytes, [int offset = 0]);
}

class StatisticsInfoResponse extends Response {
  int totalCount;
  int latestId;

  StatisticsInfoResponse(this.totalCount, this.latestId) : super(0);

  static StatisticsInfoResponse fromBytes(Uint8ClampedList bytes, [int offset = 0]) {
    Uint8 totalCount = ByteUtil.toUint8(bytes[offset]);
    offset++;
    Uint32 latestId = ByteUtil.bytes2Uint32Le(bytes, offset);
    return StatisticsInfoResponse(totalCount.value, latestId.value);
  }
}

class EucStatisticsResponse extends StatisticsResponse {
  EucStatisticsResponse(VersionWrapper versionWrapper, ProductModel model) : super(versionWrapper, model);

  @override
  void fromBytes(Uint8ClampedList bytes, [int offset = 0]) {
    index = bytes[offset++];
    count = bytes[offset++] & 0xFF;
    total = bytes[offset++] & 0xFF;
    length = bytes[offset++] & 0xFF;

    for (var i = 0; i < count; i++) {
      var s = EucStatistics(model!, versionWrapper!);
      s.fromBytes(bytes, offset);
      offset += length;
      statisticsList.add(s);
    }
  }
}

class BMSLogResponse extends Response {
  int index = 0;
  int remain = 0;

  BMSLog log = BMSLog();

  BMSLogResponse(super.error);

  static BMSLogResponse fromBytes(Uint8ClampedList bytes, {int offset = 0}) {
    var rsp = BMSLogResponse(0);
    rsp.index = ByteUtil.bytes2Uint32Le(bytes, offset).value;
    offset += 4;
    rsp.remain = ByteUtil.bytes2Uint32Le(bytes, offset).value;
    offset += 4;

    ByteUtil.copy(bytes, offset, rsp.log.bytes, 0, rsp.log.bytes.length);
    return rsp;
  }
}
